#include "stdafx.h"
#include "StateManager.h"

#include "d3dUtil.h"

using namespace mgfx;
using namespace std;

ID3D10RasterizerState * StateManager::createRasterizerState(const string & key, D3D10_RASTERIZER_DESC * desc)
{
	assert(mRasterizerStates.find(key) == mRasterizerStates.end());
	ID3D10RasterizerState * state;
	HR(mDevice->CreateRasterizerState(desc, &state));
	mRasterizerStates[key] = state;
	return state;
}

ID3D10RasterizerState * StateManager::getRasterizerState(const string & key)
{
	assert(mRasterizerStates.find(key) != mRasterizerStates.end());
	return mRasterizerStates[key];
}


ID3D10DepthStencilState * StateManager::createDepthStencilState(const string & key, D3D10_DEPTH_STENCIL_DESC * desc)
{
	assert(mDepthStencilStates.find(key) == mDepthStencilStates.end());
	ID3D10DepthStencilState * state;
	mDevice->CreateDepthStencilState(desc, &state);
	mDepthStencilStates[key] = state;
	return state;
}

ID3D10DepthStencilState * StateManager::getDepthStencilState(const string & key)
{
	assert(mDepthStencilStates.find(key) != mDepthStencilStates.end());
	return mDepthStencilStates[key];
}


ID3D10BlendState * StateManager::createBlendState(const string & key, D3D10_BLEND_DESC * desc)
{
	assert(mBlendStates.find(key) == mBlendStates.end());
	ID3D10BlendState * state;
	mDevice->CreateBlendState(desc, &state);
	mBlendStates[key] = state;
	return state;
}

ID3D10BlendState * StateManager::getBlendState(const string & key)
{
	assert(mBlendStates.find(key) != mBlendStates.end());
	return mBlendStates[key];
}


ID3D10SamplerState * StateManager::createSamplerState(const string & key, D3D10_SAMPLER_DESC * desc)
{
	assert(mSamplerStates.find(key) == mSamplerStates.end());
	ID3D10SamplerState * state;
	mDevice->CreateSamplerState(desc, &state);
	mSamplerStates[key] = state;
	return state;
}

ID3D10SamplerState * StateManager::getSamplerState(const string & key)
{
	assert(mSamplerStates.find(key) != mSamplerStates.end());
	return mSamplerStates[key];
}


void StateManager::init(ID3D10Device * device)
{
	mDevice = device;

	D3D10_RASTERIZER_DESC rsDesc;

	ZeroMemory(&rsDesc, sizeof(D3D10_RASTERIZER_DESC));
	rsDesc.CullMode = D3D10_CULL_NONE;
	rsDesc.FillMode = D3D10_FILL_SOLID;
	createRasterizerState(MGFX_RS_NO_CULLING, &rsDesc);


	D3D10_DEPTH_STENCIL_DESC dssDesc;
	ZeroMemory(&dssDesc, sizeof(D3D10_DEPTH_STENCIL_DESC));
	dssDesc.DepthEnable = true;
	dssDesc.DepthFunc = D3D10_COMPARISON_LESS;
	dssDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ZERO;
	dssDesc.StencilEnable = true;
	dssDesc.StencilReadMask = D3D10_DEFAULT_STENCIL_READ_MASK;
	dssDesc.StencilWriteMask = D3D10_DEFAULT_STENCIL_WRITE_MASK;
	
	D3D10_DEPTH_STENCILOP_DESC dsopDesc;
	ZeroMemory(&dsopDesc, sizeof(D3D10_DEPTH_STENCILOP_DESC));
	dsopDesc.StencilFunc = D3D10_COMPARISON_ALWAYS;
	dsopDesc.StencilDepthFailOp = D3D10_STENCIL_OP_INCR;
	dsopDesc.StencilPassOp = D3D10_STENCIL_OP_KEEP;
	dsopDesc.StencilFailOp = D3D10_STENCIL_OP_KEEP;
	dssDesc.BackFace = dsopDesc;

	dsopDesc.StencilDepthFailOp = D3D10_STENCIL_OP_DECR;
	dssDesc.FrontFace = dsopDesc;

	createDepthStencilState(MGFX_DSS_TWO_SIDED_STENCIL, &dssDesc);


	ZeroMemory(&dssDesc, sizeof(D3D10_DEPTH_STENCIL_DESC));
	dssDesc.DepthEnable = true;
	dssDesc.DepthFunc = D3D10_COMPARISON_LESS_EQUAL;
	dssDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ZERO;
	dssDesc.StencilEnable = true;
	dssDesc.StencilReadMask = D3D10_DEFAULT_STENCIL_READ_MASK;
	dssDesc.StencilWriteMask = 0x0;
	
	ZeroMemory(&dsopDesc, sizeof(D3D10_DEPTH_STENCILOP_DESC));
	dsopDesc.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
	dsopDesc.StencilFunc = D3D10_COMPARISON_NEVER;
	dsopDesc.StencilPassOp = D3D10_STENCIL_OP_ZERO;
	dsopDesc.StencilFailOp = D3D10_STENCIL_OP_ZERO;
	dssDesc.BackFace = dsopDesc;

	dsopDesc.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
	dsopDesc.StencilFunc = D3D10_COMPARISON_EQUAL;
	dsopDesc.StencilPassOp = D3D10_STENCIL_OP_KEEP;
	dsopDesc.StencilFailOp = D3D10_STENCIL_OP_ZERO;
	dssDesc.FrontFace = dsopDesc;

	createDepthStencilState(MGFX_DSS_AFTER_SHADOW_VOLUME_STENCIL, &dssDesc);


	D3D10_BLEND_DESC bsDesc;
	ZeroMemory(&bsDesc, sizeof(D3D10_BLEND_DESC));
	bsDesc.BlendEnable[0] = false;
	bsDesc.RenderTargetWriteMask[0] = 0x0;
	createBlendState(MGFX_BS_DISABLE_FRAMEBUFFER, &bsDesc);


	D3D10_SAMPLER_DESC ssDesc;
	ZeroMemory(&ssDesc, sizeof(D3D10_SAMPLER_DESC));
	ssDesc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
	ssDesc.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP;
	ssDesc.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP;
	ssDesc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
	createSamplerState(MGFX_SS_TRILINEAR_WRAP, &ssDesc);
	
}

void StateManager::deinit()
{
	for(RSMap::iterator it = mRasterizerStates.begin() ; it != mRasterizerStates.end() ; ++it)
		ReleaseCOM(it->second);

	for(DSSMap::iterator it = mDepthStencilStates.begin() ; it != mDepthStencilStates.end() ; ++it)
		ReleaseCOM(it->second);

	for(BSMap::iterator it = mBlendStates.begin() ; it != mBlendStates.end() ; ++it)
		ReleaseCOM(it->second);

	for(SSMap::iterator it = mSamplerStates.begin() ; it != mSamplerStates.end() ; ++it)
		ReleaseCOM(it->second);
}